package dataImport.action;

import java.util.HashMap;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import dataImport.action.abstracts.AbstractTempEntityReader;
import dataImport.action.helper.UnityGuardian;
import dataImport.action.manager.EntityReaderManager;
import dataImport.action.manager.storage.EntityReaderStorageKey;
import dataImport.exception.DuplicateAttributeException;
import dataImport.exception.MissingAttributeException;
import dataImport.exception.MissingReader;
import dataImport.exception.UniquenessRestrictionViolatedException;
import dataImport.model.Command;
import dataImport.model.CommandTemp;
import dataImport.model.abstracts.AbstractEntity;
import dataImport.model.abstracts.AbstractInteractableEntity;


public class CommandReader extends AbstractTempEntityReader {

	private static final long serialVersionUID = 3166789661223136258L;

	public static final String ENTITY_NAME = "command";

	private static final String ATTRIBUTE_PATTERN = "pattern";

	private UnityGuardian patternUniqueKey;

	public CommandReader() {
		super();
		this.patternUniqueKey = new UnityGuardian();
	}

	@Override
	protected void checkRequiredReaders(final EntityReaderManager entityReaderManager) throws MissingReader {
		entityReaderManager.contains(EntityReaderStorageKey.OBJECT);
		entityReaderManager.contains(EntityReaderStorageKey.PLACE);
		entityReaderManager.contains(EntityReaderStorageKey.NPC);
	}

	@Override
	protected AbstractEntity createEntity(final Element element) {
		final String id = element.getAttribute(ATTRIBUTE_ID);
		final String pattern = element.getAttribute(ATTRIBUTE_PATTERN);

		this.verifyRestrictions(id, pattern);

		return new CommandTemp(id, pattern);
	}

	@Override
	protected void fixEntities(HashMap<String, AbstractEntity> newEntities, EntityReaderManager entityReaderManager) throws MissingReader {
		for (final AbstractEntity abstractEntity : this.abstractEntities.values()) {
			final CommandTemp commandTemp = (CommandTemp) abstractEntity;

			final String id = commandTemp.getId();
			final String pattern = commandTemp.getPattern();

			newEntities.put(id, new Command(id, this.fixPattern(pattern, entityReaderManager)));
		}
	}

	@Override
	public void read(final Document document) {
		this.read(CommandReader.ENTITY_NAME, document);
	}

	protected final void verifyRestrictions(final String id, final String pattern) {
		super.verifyRestrictions(id);

		try {
			this.patternUniqueKey.ensureUniqueness(pattern);
		}
		catch (UniquenessRestrictionViolatedException e) {
			throw new DuplicateAttributeException("pattern", pattern);
		}

		if (pattern.isEmpty()) {
			throw new MissingAttributeException(ATTRIBUTE_PATTERN);
		}
	}

	private final String fixPattern(final String pattern, final EntityReaderManager entityReaderManager) throws MissingReader {
		String newPattern = pattern;

		final PlaceReader placeReader = entityReaderManager.getPlaceReader();
		newPattern = super.fixText(newPattern, PlaceReader.ENTITY_NAME, placeReader);

		final ObjectReader objectReader = entityReaderManager.getObjectReader();
		newPattern = super.fixText(newPattern, ObjectReader.ENTITY_NAME, objectReader);

		final NpcReader npcReader = entityReaderManager.getNpcReader();
		newPattern = super.fixText(newPattern, NpcReader.ENTITY_NAME, npcReader);

		return newPattern;
	}

	@Override
	protected String replaceAll(final String text, final String regex, final AbstractEntity abstractEntity) {
		AbstractInteractableEntity abstractInteractableEntity = (AbstractInteractableEntity) abstractEntity;
		return text.replaceAll(regex, abstractInteractableEntity.getName());
	}
}
